import { Map } from 'ol'
import { Draw } from 'ol/interaction'
import VectorSource from 'ol/source/Vector'
import { Polygon } from 'ol/geom'
import VectorLayer from 'ol/layer/Vector'
import { Stroke, Style } from 'ol/style'
import { createBox } from 'ol/interaction/Draw'

/**
 * 屏幕截图工具类，提供全图导出和框选区域导出功能
 * @example
 * //底图需要设置跨域属性
  const source = layer?.getSource() as XYZ | WMTS
  source.setTileLoadFunction((tile: any, url) => {
    const image = tile.getImage() as HTMLImageElement
    image.crossOrigin = 'anonymous' // 为每个瓦片设置跨域属性
    image.src = url
  })
 */
export class ScreenShotTool {
  private map: Map | undefined // OpenLayers地图实例
  private draw: Draw | undefined // 绘制交互实例
  private drawLayer: VectorLayer | undefined // 绘制图层
  private selectedArea: Polygon | undefined // 用户选择的区域
  private source = new VectorSource() // 矢量数据源

  constructor(map: Map) {
    this.map = map
  }

  /**
   * 导出整个地图为PNG图片
   */
  exportMap() {
    if (!this.map) return

    // 获取地图的canvas元素
    const canvas = this.map.getTargetElement().querySelector('canvas') as HTMLCanvasElement

    // 创建临时canvas
    const tempCanvas = document.createElement('canvas')
    const ctx = tempCanvas.getContext('2d') as CanvasRenderingContext2D

    // 设置临时canvas尺寸与地图canvas一致
    tempCanvas.width = canvas.width
    tempCanvas.height = canvas.height

    // 将地图canvas内容绘制到临时canvas
    ctx.drawImage(canvas, 0, 0)

    // 创建下载链接并触发下载
    const link = document.createElement('a')
    link.download = `map_${this.getCurrentTime()}.png`
    link.href = tempCanvas.toDataURL('image/png')
    link.click()
  }

  /**
   * 开始绘制选择区域
   */
  startDraw() {
    if (!this.map) return

    // 清除现有绘制交互
    if (this.draw) {
      this.map.removeInteraction(this.draw)
    }

    // 设置绘制样式
    const style = new Style({
      stroke: new Stroke({
        color: 'rgba(0, 255, 0, 1)', // 绿色描边
        width: 2 // 描边宽度
      })
    })

    // 初始化或重置绘制图层
    if (!this.drawLayer) {
      this.drawLayer = new VectorLayer({
        source: this.source,
        style
      })
      this.drawLayer.set('id', 'drawLayer')
      this.map.addLayer(this.drawLayer)
    } else {
      this.drawLayer.getSource()?.clear()
    }

    // 创建矩形绘制交互
    this.draw = new Draw({
      source: this.source,
      type: 'Circle', // 使用Circle类型但通过geometryFunction转换为矩形
      geometryFunction: createBox(), // 将绘制转换为矩形
      style
    })

    this.map.addInteraction(this.draw)

    // 绘制结束事件处理
    this.draw.on('drawend', (e) => {
      this.selectedArea = e.feature.getGeometry() as Polygon
      this.map && this.map.removeInteraction(this.draw!)
    })
  }

  /**
   * 导出框选区域的地图为PNG图片
   */
  exportFrameSelected() {
    if (!this.map || !this.selectedArea) return
    let drawLayer = this.drawLayer
    if (!drawLayer) return

    // 隐藏绘制图层避免出现在截图中
    drawLayer.setVisible(false)

    // 延迟执行确保图层已隐藏
    setTimeout(() => {
      if (!this.map || !this.selectedArea) return

      // 获取地图canvas
      const canvas = this.map.getTargetElement().querySelector('canvas') as HTMLCanvasElement

      // 创建临时canvas
      const tempCanvas = document.createElement('canvas')
      const ctx = tempCanvas.getContext('2d') as CanvasRenderingContext2D

      // 获取选择区域的范围
      const extent = this.selectedArea!.getExtent()
      // 转换为像素坐标
      const bottomLeft = this.map.getPixelFromCoordinate([extent[0], extent[1]]) // 左下角
      const topRight = this.map.getPixelFromCoordinate([extent[2], extent[3]]) // 右上角

      // 计算选择区域的宽高
      const width = topRight[0] - bottomLeft[0]
      const height = bottomLeft[1] - topRight[1] // 注意Y轴方向

      // 设置临时canvas尺寸
      tempCanvas.width = width
      tempCanvas.height = height

      // 只绘制选择区域部分
      ctx.drawImage(
        canvas,
        bottomLeft[0], // 源x坐标
        topRight[1], // 源y坐标
        width, // 源宽度
        height, // 源高度
        0, // 目标x坐标
        0, // 目标y坐标
        width, // 目标宽度
        height // 目标高度
      )

      // 创建下载链接并触发下载
      const link = document.createElement('a')
      link.download = `map-selection_${this.getCurrentTime()}.png`
      link.href = tempCanvas.toDataURL('image/png')
      link.click()

      // 恢复绘制图层可见性
      drawLayer.setVisible(true)
    }, 200)
  }

  /**
   * 生成当前时间戳字符串
   * @returns 格式化的时间字符串 (YYYY-MM-DD_HH-mm-ss)
   */
  private getCurrentTime() {
    const now = new Date()
    const year = now.getFullYear()
    const month = String(now.getMonth() + 1).padStart(2, '0')
    const day = String(now.getDate()).padStart(2, '0')
    const hours = String(now.getHours()).padStart(2, '0')
    const minutes = String(now.getMinutes()).padStart(2, '0')
    const seconds = String(now.getSeconds()).padStart(2, '0')
    const timestamp = `${year}-${month}-${day}_${hours}-${minutes}-${seconds}`
    return timestamp
  }
}
